﻿/*----------------------------------------------------------------
//  <copyright file="AliyunSmsInquirer.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2023-12-06 10:23</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.SMS.Inquirer
{
    #region "阿里云短信查询者"
    /// <summary>
    /// 阿里云短信查询者
    /// </summary>
    public class AliyunSmsInquirer : ISmsInquirer
    {
        #region 属性
        #region "获取 服务提供者对象"
        /// <summary>
        /// 获取 服务提供者对象
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus => ServiceProvider.GetService<IEventBus>();
        #endregion
        #region "获取 日志对象"
        /// <summary>
        /// 获取 日志对象
        /// </summary>
        protected ILogger Logger { get; }
        #endregion
        #region "获取 短信配置选项"
        /// <summary>
        /// 获取 短信配置选项
        /// </summary>
        protected SmsOptions SmsOpt => ServiceProvider.GetService<IConfiguration>()?.GetSmsOptions();
        #endregion

        #region "获取 HttpClient工厂对象"
        /// <summary>
        /// 获取 HttpClient工厂对象
        /// </summary>
        protected IHttpClientFactory HttpClientFactory => ServiceProvider.GetService<IHttpClientFactory>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个阿里云短信查询者的新实例"
        /// <summary>
        /// 初始化一个阿里云短信查询者 <see cref="AliyunSmsInquirer"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public AliyunSmsInquirer(IServiceProvider provider)
        {
            ServiceProvider = provider;
            Logger = provider.GetLogger(GetType());
        }
        #endregion

        #endregion

        #region "方法"
        #region "查询短信发送状态"
        /// <summary>
        /// 查询短信发送状态
        /// </summary>
        /// <param name="paramsDto">短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<StatusResponse>> QuerySentStatusAsync(QueryParamsDto paramsDto)
        {
            var result = OperationResult.Unsupported<StatusResponse>(I18N.T("阿里云不支持查询短信发送状态"));
            //触发状态查询成功事件
            if (result.Succeeded)
            {
                SmsStatusEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion
        #region "查询短信发送记录"
        /// <summary>
        /// 查询短信发送记录
        /// </summary>
        /// <param name="paramsDto">短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<QueryResponse>> QuerySentDetailsAsync(QueryParamsDto paramsDto)
        {
            var result = QuerySentDetailsByAliyun(SmsOpt.RegionId, SmsOpt.Id, SmsOpt.Secret
                        , SmsOpt.Domain
                        , paramsDto.PhoneNumber, paramsDto.SendDate
                        , paramsDto.PageSize, paramsDto.CurrentPage
                        , paramsDto.BizId);
            //触发查询成功事件
            if (result.Succeeded)
            {
                SmsQueryEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion
        #region "查询上行短信消息"
        /// <summary>
        /// 查询上行短信消息
        /// </summary>
        /// <param name="paramsDto">上行短信查询参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<UpResponse>> QueryUpDetailsAsync(UpParamsDto paramsDto)
        {
            var result = OperationResult.Unsupported<UpResponse>(I18N.T("阿里云不支持查询上行短信消息"));
            //触发查询成功事件
            if (result.Succeeded)
            {
                SmsUpEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "以阿里云作为服务商查询短信发送记录"
        /// <summary>
        /// 以阿里云作为服务商查询短信发送记录
        /// </summary>
        /// <param name="regionId">区域ID cn-hangzhou</param>
        /// <param name="accessKeyId">阿里云API的密钥Id</param>
        /// <param name="accessKeySecret">阿里云API的密钥Secret</param>
        /// <param name="domain">产品域名 dysmsapi.aliyuncs.com</param>
        /// <param name="phoneNumber">接收短信的手机号码</param>
        /// <param name="sendDate">短信发送日期</param>
        /// <param name="pageSize">分页查看发送记录，指定每页显示的短信记录数量</param>
        /// <param name="currentPage">分页查看发送记录，指定发送记录的的当前页码</param>
        /// <param name="bizId">发送回执ID，即发送流水号。调用发送接口SendSms或SendBatchSms发送短信时，返回值中的BizId字段。</param>
        /// <returns></returns>
        protected virtual OperationResult<QueryResponse> QuerySentDetailsByAliyun(string regionId, string accessKeyId, string accessKeySecret
            //, string Product <param name="Product">产品名称 Dysmsapi</param>
            , string domain
            , string phoneNumber, DateTime sendDate
            , long pageSize, long currentPage
            , string bizId
            )
        {
            regionId = regionId.IsMissing() ? AliyunConstants.RegionId : regionId;
            //Product = Product.IsMissing() ? AliyunConstants.Product : Product;
            domain = domain.IsMissing() ? AliyunConstants.Domain : domain;

            Check.NotNullOrEmpty(accessKeyId, nameof(accessKeyId));
            Check.NotNullOrEmpty(accessKeySecret, nameof(accessKeySecret));

            Check.NotNullOrEmpty(phoneNumber, nameof(phoneNumber));
            if (pageSize < 1 || pageSize > 50)
            {
                throw new Exception(I18N.T("以阿里云作为服务商发送短信错误：分页查看发送记录，指定每页显示的短信记录数量必须介于 1~50。"));
            }

            //设置短息处理程序
            IClientProfile profile = DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret);
            DefaultAcsClient client = new(profile);
            CommonRequest request = new();
            request.Method = MethodType.POST;
            request.Domain = domain;
            request.Version = AliyunConstants.Version;
            request.Action = AliyunConstants.QuerySendDetailsAction;
            // request.Protocol = ProtocolType.HTTP;

            //*必填：接收短信的手机号码。
            //国内短信：11位手机号码，例如15900000000。
            //国际&港澳台消息：国际区号 + 号码，例如85200000000。
            request.AddQueryParameters("PhoneNumber", phoneNumber);

            //*必填：短信发送日期，支持查询最近30天的记录。
            //格式为yyyyMMdd，例如20181225。
            request.AddQueryParameters("SendDate", sendDate.ToString("yyyyMMdd"));

            //*必填：分页查看发送记录，指定每页显示的短信记录数量。
            //取值范围为1~50。
            request.AddQueryParameters("PageSize", pageSize.ToString());

            //*必填：分页查看发送记录，指定发送记录的的当前页码。
            request.AddQueryParameters("CurrentPage", currentPage.ToString());

            //可选：发送回执ID，即发送流水号。调用发送接口SendSms或SendBatchSms发送短信时，返回值中的BizId字段。
            if (!bizId.IsMissing())
            {
                request.AddQueryParameters("BizId", bizId);
            }

            try
            {
                CommonResponse response = client.GetCommonResponse(request);
                var smsQueryResponse = response.Data.FromJsonString<QueryResponse>();
                if (!smsQueryResponse.Succeeded)
                {
                    return OperationResult.Error(smsQueryResponse);
                }
                return OperationResult.Success(smsQueryResponse);
            }
            catch (ServerException e)
            {
                Logger.LogError(e, "{msg}", e.Message);
                return OperationResult.Error<QueryResponse>(e.Message);
            }
            catch (ClientException e)
            {
                Logger.LogError(e, "{msg}", e.Message);
                return OperationResult.Error<QueryResponse>(e.Message);
            }
        }
        #endregion

        #endregion

    }
    #endregion

}
